#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
构建可执行文件的脚本
使用PyInstaller将Flask应用打包成Windows可执行文件（one-dir模式）
"""

import os
import sys
import shutil
import subprocess
from pathlib import Path
import json

def install_pyinstaller():
    """安装PyInstaller"""
    print("正在安装PyInstaller...")
    try:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
        print("PyInstaller安装成功！")
    except subprocess.CalledProcessError as e:
        print(f"PyInstaller安装失败: {e}")
        return False
    return True

def create_spec_file():
    """创建PyInstaller规格文件（one-dir模式）"""
    spec_content = '''
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['app.py'],
    pathex=[],
    binaries=[],
    datas=[
        ('templates', 'templates'),
        ('static', 'static'),
    ],
    hiddenimports=[
        'flask',
        'werkzeug',
        'jinja2',
        'markupsafe',
        'itsdangerous',
        'click',
        'blinker',
        'socket',
        'urllib.parse',
        'requests',
    ],
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    exclude_binaries=True,
    name='navigation_platform',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon='static/favicon.ico' if os.path.exists('static/favicon.ico') else None,
)

# 创建目录模式的构建配置
dir = COLLECT(
    exe,
    a.binaries,
    a.zipfiles,
    a.datas,
    strip=False,
    upx=True,
    upx_exclude=[],
    name='navigation_platform',
)
'''
    
    with open('navigation_platform.spec', 'w', encoding='utf-8') as f:
        f.write(spec_content)
    print("已创建PyInstaller规格文件: navigation_platform.spec")

def build_executable():
    """构建可执行文件"""
    print("开始构建可执行文件...")
    try:
        # 使用spec文件构建
        subprocess.check_call([
            sys.executable, '-m', 'PyInstaller', 
            '--clean',
            'navigation_platform.spec'
        ])
        print("可执行文件构建成功！")
        return True
    except subprocess.CalledProcessError as e:
        print(f"构建失败: {e}")
        return False

def prepare_config_files():
    """准备配置文件目录和文件"""
    # 创建dist/navigation_platform目录（one-dir模式的输出目录）
    dist_app_dir = Path('dist/navigation_platform')
    if not dist_app_dir.exists():
        # 如果目录不存在，创建它
        print("正在创建dist/navigation_platform目录...")
        try:
            dist_app_dir.mkdir(parents=True, exist_ok=True)
            print("已创建dist/navigation_platform目录")
        except Exception as e:
            print(f"创建目录失败: {e}")
            return
    
    # 创建config目录
    config_dir = dist_app_dir / 'config'
    config_dir.mkdir(exist_ok=True)
    print("已创建配置目录: dist/navigation_platform/config")
    
    # 检查配置文件是否存在，不存在则抛出错误
    if not os.path.exists('config/sites_config.json'):
        raise FileNotFoundError("配置文件夹缺失: 找不到 'config/sites_config.json' 文件。请确保配置文件夹存在且包含正确的配置文件。")
    
    # 复制配置文件
    shutil.copy2('config/sites_config.json', config_dir)
    print("已复制配置文件: config/sites_config.json")
    
    # 复制README文件和其他必要文件
    files_to_copy = [
        'README.md',
        'DOCKER_DEPLOY.md',
        'requirements.txt'
    ]
    
    for file_name in files_to_copy:
        if os.path.exists(file_name):
            shutil.copy2(file_name, dist_app_dir)
            print(f"已复制 {file_name} 到 dist/navigation_platform 目录")

def clean_previous_build():
    """清理之前的构建文件"""
    import time
    print("正在清理之前的构建文件...")
    
    # 删除dist目录（one-dir模式的输出目录）
    if os.path.exists('dist'):
        for attempt in range(3):
            try:
                shutil.rmtree('dist')
                print("已删除 dist 目录")
                break
            except Exception as e:
                if attempt < 2:
                    print(f"删除 dist 目录失败，重试中... ({attempt + 1}/3)")
                    time.sleep(1)
                else:
                    print(f"删除 dist 目录失败: {e}")
    
    # 删除build目录
    if os.path.exists('build'):
        try:
            shutil.rmtree('build')
            print("已删除 build 目录")
        except Exception as e:
            print(f"删除 build 目录失败: {e}")
    
    # 删除spec文件
    spec_files = ['navigation_platform.spec', 'app.spec']
    for spec_file in spec_files:
        if os.path.exists(spec_file):
            try:
                os.remove(spec_file)
                print(f"已删除 {spec_file}")
            except Exception as e:
                print(f"删除 {spec_file} 失败: {e}")
    
    print("清理完成！\n")

def main():
    """主函数"""
    print("=" * 50)
    print("Flask应用打包工具 (one-dir模式)")
    print("=" * 50)
    
    # 清理之前的构建文件
    clean_previous_build()
    
    # 检查是否安装了PyInstaller
    try:
        import PyInstaller
        print("PyInstaller已安装")
    except ImportError:
        if not install_pyinstaller():
            return
    
    # 创建规格文件
    create_spec_file()
    
    # 构建可执行文件
    if build_executable():
        # 准备配置文件
        try:
            prepare_config_files()
        except FileNotFoundError as e:
            print(f"配置错误: {e}")
            print("构建失败，请先创建配置文件后再尝试打包。")
            return
        
        print("\n" + "=" * 50)
        print("构建完成！")
        print("=" * 50)
        print("应用目录位置: dist/navigation_platform")
        print("配置文件位置: dist/navigation_platform/config/sites_config.json")
        print("\n使用方法:")
        print("1. 直接运行 'dist/navigation_platform/navigation_platform.exe'")
        print("2. 在浏览器中访问 http://localhost:5000")
        print("\n配置说明:")
        print("- 配置文件支持外部修改")
        print("- 修改后需要重启应用生效")
        print("\n注意: 首次运行可能需要较长时间加载")
    else:
        print("构建失败，请检查错误信息")

if __name__ == '__main__':
    main()